#include "Login.h"
#include "ui_Login.h"

Login::Login(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Login)
{
    ui->setupUi(this);
    // 设置固定大小
    setFixedSize(313,424);
    initSettings();// 初始化配置文件
    initUI();// 初始化UI(包括加载初始头像、添加验证器等)
    initConnect();// 连接服务器
}

Login::~Login()
{
    delete ui;
}

void Login::initUI()
{
    // 1.初始化头像（本地保存的或者默认的）

    QPixmap avatar;
    // 到本地应用程序目录查看是否有保存的本地头像
    QString appDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
    QDir dir(appDir);// 创建成目录
    // 尝试获取头像文件路径
    QString avatarPath = dir.filePath("lastLoginAvatar.png");
    if(QFile::exists(avatarPath) && avatar.load(avatarPath)){
        // 说明存在并加载成功
    }
    else{
        // 使用默认的头像
        avatar.load(":/images/login/defult_avatar.png");
    }
    // 设置头像到控件
    ui->avatarLabel->setPixmap(avatar.scaled(150,150,Qt::KeepAspectRatioByExpanding,Qt::SmoothTransformation));


    // 2.初始化账号和密码框的验证器

    // 设置正则表达式对象
    QRegularExpression idRegExp("^[1-9][0-9]{11}$");// 账号：12位纯数字，第一位不能是0
    QRegularExpression pwdRegExp("^[a-zA-Z0-9]{1,8}$");// 密码：1-8位，仅包含英文大小写和数字
    QRegularExpressionValidator* idValidator = new QRegularExpressionValidator(idRegExp,ui->idLineEdit);
    QRegularExpressionValidator* pwdValidator = new QRegularExpressionValidator(pwdRegExp,ui->pwdLineEdit);
    // 安装给账号和密码输入框
    ui->idLineEdit->setValidator(idValidator);
    ui->pwdLineEdit->setValidator(pwdValidator);

    // 3.根据配置文件，初始化账号、密码、和记住密码、自动登录框
    QString id = m_settings->value("last_id","").toString();// 尝试取出上次登陆的账号
    QString pwd = m_settings->value("last_pwd","").toString();
    QString remPwd = m_settings->value("remember_pwd","").toString();
    QString autLogin = m_settings->value("auto_login","").toString();
    // 如果记录了自动登录，账号和密码肯定都是不为空
    if(!autLogin.isEmpty()){
        ui->autoLoginCheckBox->setChecked(true);
        ui->idLineEdit->setText(id);
        ui->pwdLineEdit->setText(pwd);
        setEnableUI(false);
        ui->autoLoginCheckBox->setEnabled(true);// 允许不进行自动登录
        QTimer::singleShot(4000,[=](){
            // 4秒后自动登录,在此期间用户如果取消了自动登录，则不发送信号
            if(ui->autoLoginCheckBox->isChecked()){
                ui->loginBtn->clicked();
            }else{
                setEnableUI(true);
            }
        });
    }
    // 如果记录了记住密码，账号和密码肯定都是不为空
    else if(!remPwd.isEmpty()){
        ui->rememberPwdCheckBox->setChecked(true);
        ui->idLineEdit->setText(id);
        ui->pwdLineEdit->setText(pwd);
    }
    // 如果上次登陆账号不为空，显示账号
    else if(!id.isEmpty()){
        ui->idLineEdit->setText(id);
    }


    // 4.设置焦点，避免一开始自动定位到输入框（太难看）
    ui->findPwdBtn->setFocus();
}

void Login::initSettings()
{
    // 存储上次登陆的账号、密码、是否记住密码、是否自动登录信息
    m_settings = new QSettings("myData.ini",QSettings::IniFormat);
}

void Login::initConnect()
{
    // 实例化套接字对象
    m_socket = new QWebSocket();

    // 链接信号和槽
    connect(m_socket,&QWebSocket::connected,this,&Login::onConnected);
    connect(m_socket,&QWebSocket::disconnected,this,&Login::onDisconnected);
    connect(m_socket,&QWebSocket::textMessageReceived,this,&Login::onTextMessageRecrived);

    // 连接服务端，如果服务端不运行在本地，则将localhost改为相应的ip地址
    m_socket->open(QUrl("ws://localhost:8899"));
}

void Login::sendJsonToServer(QJsonObject &jsonObj)
{
    jsonObj["end"] = "end";// 添加结束标志
    QJsonDocument jsonDoc(jsonObj);
    QByteArray jsonData = jsonDoc.toJson();
    QString jsonStr = QString::fromUtf8(jsonData);
    m_socket->sendTextMessage(jsonStr);
    m_socket->flush();
}

void Login::setEnableUI(bool flag)
{
    ui->idLineEdit->setEnabled(flag);
    ui->pwdLineEdit->setEnabled(flag);
    ui->loginBtn->setEnabled(flag);
    ui->registerBtn->setEnabled(flag);
    ui->findPwdBtn->setEnabled(flag);
    ui->rememberPwdCheckBox->setEnabled(flag);
    ui->autoLoginCheckBox->setEnabled(flag);
}

void Login::saveAvatar(QPixmap avatar)
{
    // 将图片保存到本地目录中
    QString dirPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
    QDir dir(dirPath);

    // 确保目录存在，如果不存在则创建
    if (!dir.exists()) {
        if (!dir.mkpath(dirPath)) {
            qDebug() << "无法创建目录:" << dirPath;
            return;
        }
    }

    // 合成路径
    QString path = dirPath + QDir::separator() + "lastLoginAvatar.png";

    QImage image = avatar.toImage();
    if(!image.save(path,"PNG")){
        qDebug()<<"登录成功后将头像以png格式保存到本地的逻辑失败";
    }
}


QWebSocket *Login::getSocket()
{
    return m_socket;
}

void Login::dealRegister(const QJsonObject &jsonObj)
{
    if(jsonObj["reply"].toString() == "faild"){
        QMessageBox::warning(this,"警告","账号注册失败，请稍后重试");
    }else if(jsonObj["reply"].toString() == "succeed"){
        ui->idLineEdit->setText(jsonObj["id"].toString());
        ui->pwdLineEdit->setText(jsonObj["pwd"].toString());
    }
}

void Login::dealLogin(const QJsonObject &jsonObj)
{
    if(jsonObj["reply"].toString() == "faild"){
        if(jsonObj["note"].toString().isEmpty()){
            QMessageBox::warning(this,"警告","账号登录失败，请检查账号密码");
        }else{
            QMessageBox::warning(this,"警告","账号已经登陆，请稍后重试");
        }
        setEnableUI(true);

    }else if(jsonObj["reply"].toString() == "succeed"){
        // 如果登录成功，设置配置信息的值
        m_settings->setValue("last_id",ui->idLineEdit->text());
        m_settings->setValue("last_pwd",ui->pwdLineEdit->text());

        if(ui->autoLoginCheckBox->isChecked()){
            m_settings->setValue("auto_login","yes");// 有值就行
        }else{
            m_settings->remove("auto_login");
        }

        if(ui->rememberPwdCheckBox->isChecked()){
            m_settings->setValue("remember_pwd","yes");// 有值就行
        }else{
            m_settings->remove("remember_pwd");
        }

        // 保存头像到本地
        saveAvatar(ui->avatarLabel->pixmap());

        // 关闭登录窗口，换成主窗口
        emit loginSucceed(jsonObj["id"].toString());
    }
}

void Login::dealFindPwdStep3(const QString &reply)
{
    if(reply == "faild"){
        ui->pwdLineEdit->clear();
        QMessageBox::warning(this,"警告","密码修改失败");
    }else if(reply == "succeed"){
        // 密码修改成功
    }
    setEnableUI(true);
}

void Login::dealFindPwdStep1(const QString& reply, const QString& safeQ)
{
    // 将回答返还给找回密码类
    emit findPwdStep1(reply,safeQ);
}

void Login::dealFindPwdStep2(const QString& reply)
{
    // 将回答返还给找回密码类
    emit findPwdStep2(reply);
}

void Login::onConnected()
{
    qDebug()<<"成功连接服务器";
}

void Login::onDisconnected()
{
    QMessageBox msgBox;
    msgBox.setWindowTitle("错误");
    msgBox.setText("服务器连接失败或中断，是否重新尝试连接？");
    msgBox.setIcon(QMessageBox::Warning);

    // 添加确认和取消按钮
    QPushButton *retryButton = msgBox.addButton("重试", QMessageBox::AcceptRole);
    QPushButton *cancelButton = msgBox.addButton("取消", QMessageBox::RejectRole);

    msgBox.exec();  // 以模态方式运行对话框

    // 判断用户选择
    if (msgBox.clickedButton() == retryButton) {
        initConnect();// 尝试重新连接服务器
    }
    else if(msgBox.clickedButton() == cancelButton){
        close();// 用户选择取消则直接退出程序
    }else{
        close();// 用户用户叉掉也直接退出程序
    }
}

void Login::onTextMessageRecrived(const QString &message)
{
    // 检查收到的数据是不是json格式
    QJsonDocument jsonDoc = QJsonDocument::fromJson(message.toUtf8());
    if(!jsonDoc.isObject()){
        qDebug()<<"客户端收到一条非法数据";
        return;
    }

    // 转为json对象
    QJsonObject jsonObj = jsonDoc.object();
    if(jsonObj["end"] != "end"){
        qDebug()<<"客户端收到一条没有结束标志的非法数据";
        return;
    }

    //根据json["tag"]标签进行分类处理
    QString tag = jsonObj["tag"].toString();

    if(tag == "register"){
        dealRegister(jsonObj);
    }
    else if(tag == "login"){
        dealLogin(jsonObj);
    }
    else if(tag == "findPwdStep1"){
        dealFindPwdStep1(jsonObj["reply"].toString(),jsonObj["safeQ"].toString());
    }
    else if(tag == "findPwdStep2"){
        dealFindPwdStep2(jsonObj["reply"].toString());
    }
    else if(tag == "findPwdStep3"){
        dealFindPwdStep3(jsonObj["reply"].toString());
    }
}

void Login::onRegisterData(QJsonObject &jsonObj)
{
    // 1.设置登录界面上的头像数据
    QString avatarStr = jsonObj["avatar"].toString();
    QByteArray byteArray = QByteArray::fromBase64(avatarStr.toUtf8());

    QImage avatarImage = QImage::fromData(byteArray);
    if(!avatarImage.isNull()){
        QPixmap avatarPix = QPixmap::fromImage(avatarImage);
        ui->avatarLabel->setPixmap(avatarPix.scaled(150,150,Qt::KeepAspectRatioByExpanding,Qt::SmoothTransformation));
    }else{
        QMessageBox::warning(this,"警告","选择的头像是无效的");
    }

    // 2.发送注册消息给服务端
    sendJsonToServer(jsonObj);
}

void Login::onFindPwdStep2(const QString& id,const QString &safeA)
{
    // 将找回密码第二步的回答发给服务端
    QJsonObject jsonObj;
    jsonObj["tag"] = "findPwdStep2";
    jsonObj["id"] = id;
    jsonObj["safeA"] = safeA;
    sendJsonToServer(jsonObj);
}

void Login::onFindPwdStep3(const QString &id, const QString &pwd)
{
    // 将登陆界面的账号和密码改为当前的
    ui->idLineEdit->setText(id);
    ui->pwdLineEdit->setText(pwd);

    // 接收到修改回答前，不能动ui
    setEnableUI(false);

    // 发送修改请求给服务端
    QJsonObject jsonObj;
    jsonObj["tag"] = "findPwdStep3";
    jsonObj["id"] = id;
    jsonObj["pwd"] = pwd;
    sendJsonToServer(jsonObj);
}

void Login::onFindPwdStep1(const QString& id)
{
    // 将找回密码第一步的账号发给服务端
    QJsonObject jsonObj;
    jsonObj["tag"] = "findPwdStep1";
    jsonObj["id"] = id;
    sendJsonToServer(jsonObj);
}

void Login::on_registerBtn_clicked()
{
    // 以模态的形式打开注册窗口
    Register* re = new Register(this);
    connect(re,&Register::registerData,this,&Login::onRegisterData);

    re->exec();

    // 窗口关闭后就断开连接
    disconnect(re,&Register::registerData,this,&Login::onRegisterData);

    re->deleteLater();
}


void Login::on_loginBtn_clicked()
{
    QString id = ui->idLineEdit->text();
    QString pwd = ui->pwdLineEdit->text();
    if(id.isEmpty() || pwd.isEmpty()){
        QMessageBox::warning(this,"警告","账号或密码不能为空");
    }

    // 设置一些ui不能点击或输入
    setEnableUI(false);

    // 发送登录账号的请求
    QJsonObject jsonObj;
    jsonObj["tag"] = "login";
    jsonObj["id"] = id;
    jsonObj["pwd"] = pwd;
    sendJsonToServer(jsonObj);
}


void Login::on_findPwdBtn_clicked()
{
    // 打开找回密码的窗口
    FindPwd* findPwd = new FindPwd();
    connect(findPwd,&FindPwd::findPwdStep1,this,&Login::onFindPwdStep1);
    connect(findPwd,&FindPwd::findPwdStep2,this,&Login::onFindPwdStep2);
    connect(findPwd,&FindPwd::findPwdStep3,this,&Login::onFindPwdStep3);
    connect(this,&Login::findPwdStep1,findPwd,&FindPwd::onFindPwdStep1);
    connect(this,&Login::findPwdStep2,findPwd,&FindPwd::onFindPwdStep2);

    findPwd->exec();

    disconnect(findPwd,&FindPwd::findPwdStep1,this,&Login::onFindPwdStep1);
    disconnect(findPwd,&FindPwd::findPwdStep2,this,&Login::onFindPwdStep2);
    disconnect(findPwd,&FindPwd::findPwdStep3,this,&Login::onFindPwdStep3);
    disconnect(this,&Login::findPwdStep1,findPwd,&FindPwd::onFindPwdStep1);
    disconnect(this,&Login::findPwdStep2,findPwd,&FindPwd::onFindPwdStep2);

    findPwd->deleteLater();// 释放找回密码窗口内存
}


void Login::on_autoLoginCheckBox_checkStateChanged(const Qt::CheckState &arg1)
{
    // 当自动登录按钮被点击，记住密码按钮也要被点击
    if(arg1 == Qt::Checked){
        ui->rememberPwdCheckBox->setChecked(true);
    }
}

